﻿#pragma once

#include <iostream>
#include <memory>
#include <sstream>
#include <vector>
#include <cassert>
#include "log_message.hpp"


namespace Local_Log
{
	/*
std::vector<FormatItem::ptr> items成员：⽤于按序保存格式化字符串对应的⼦格式化对象。
FormatItem类主要负责⽇志消息⼦项的获取及格式化。其包含以下⼦类
• MsgFormatItem ：表⽰要从LogMsg中取出有效⽇志数据
• LevelFormatItem ：表⽰要从LogMsg中取出⽇志等级
• NameFormatItem ：表⽰要从LogMsg中取出⽇志器名称
• ThreadFormatItem ：表⽰要从LogMsg中取出线程ID
• TimeFormatItem ：表⽰要从LogMsg中取出时间戳并按照指定格式进⾏格式化
• CFileFormatItem ：表⽰要从LogMsg中取出源码所在⽂件名
• CLineFormatItem ：表⽰要从LogMsg中取出源码所在⾏号
• TabFormatItem ：表⽰⼀个制表符缩进
• NLineFormatItem ：表⽰⼀个换⾏
• OtherFormatItem ：表⽰⾮格式化的原始字符串
*/
//基类
	class Base_FormatItem
	{
	public:
		using ptr = std::shared_ptr<Base_FormatItem>;
		virtual void  Format(std::ostream& out, const Log_Msg& msg) = 0;
	};
	//MsgFormatItem ：表⽰要从LogMsg中取出有效⽇志数据
	class MsgFormatItem :public Base_FormatItem
	{
	public:
		void  Format(std::ostream& out, const Log_Msg& msg)override
		{
			out << msg._payload;
		}
	};
	//LevelFormatItem ：表⽰要从LogMsg中取出⽇志等级
	class LevelFormatItem :public Base_FormatItem
	{
	public:
		void  Format(std::ostream& out, const Log_Msg& msg)override
		{
			out << Log_level::LevelToString(msg._level);
		}
	};
	//NameFormatItem ：表⽰要从LogMsg中取出⽇志器名称
	class NameFormatItem :public Base_FormatItem
	{
	public:
		void  Format(std::ostream& out, const Log_Msg& msg)override
		{
			out << msg._logger;
		}
	};
	//ThreadFormatItem ：表⽰要从LogMsg中取出线程ID
	class ThreadFormatItem :public Base_FormatItem
	{
	public:
		void  Format(std::ostream& out, const Log_Msg& msg)override
		{
			out << msg._id;
		}
	};
	//TimeFormatItem ：表⽰要从LogMsg中取出时间戳并按照指定格式进⾏格式化
	class TimeFormatItem :public Base_FormatItem
	{
	public:
		TimeFormatItem(const std::string& format = "%H:%M:%S") :_format(format) {}

		void  Format(std::ostream& out, const Log_Msg& msg)override
		{
			time_t lo_now = time(nullptr);
			// 线程安全转换（Windows用localtime_s，Linux用localtime_r）
			std::tm lo_time;
#ifdef _WIN32 
			localtime_s(&lo_time, &lo_now);
#else 
			localtime_r(&lo_now, &lo_time);
#endif 
			char lo_tmp[64];
			strftime(lo_tmp, sizeof(lo_tmp) - 1, _format.c_str(), &lo_time);
			out << lo_tmp;
		}
	private:
		std::string _format;
	};
	//CFileFormatItem ：表⽰要从LogMsg中取出源码所在⽂件名
	class CFileFormatItem :public Base_FormatItem
	{
	public:
		void  Format(std::ostream& out, const Log_Msg& msg)override
		{
			out << msg._file;
		}
	};
	//CLineFormatItem ：表⽰要从LogMsg中取出源码所在⾏号
	class CLineFormatItem :public Base_FormatItem
	{
	public:
		void  Format(std::ostream& out, const Log_Msg& msg)override
		{
			out << msg._line;
		}
	};
	//TabFormatItem ：表⽰⼀个制表符缩进
	class TabFormatItem :public Base_FormatItem
	{
	public:
		void  Format(std::ostream& out, const Log_Msg& msg)override
		{
			out << "\t";
		}
	};
	//NLineFormatItem ：表⽰⼀个换⾏
	class NLineFormatItem :public Base_FormatItem
	{
	public:
		void  Format(std::ostream& out, const Log_Msg& msg)override
		{
			out << "\n";
		}
	};
	//OtherFormatItem ：表⽰⾮格式化的原始字符串
	class OtherFormatItem :public Base_FormatItem
	{
	public:
		OtherFormatItem(const std::string& other = "") :_other(other) {}
		void  Format(std::ostream& out, const Log_Msg& msg)override
		{
			out << _other;
		}
	private:
		std::string _other;
	};


	/*
	pattern成员：保存⽇志输出的格式字符串。
	• %d ⽇期
	• %T 缩进
	• %t 线程id
	• %p ⽇志级别
	• %c ⽇志器名称
	• %f ⽂件名
	• %l ⾏号
	• %m ⽇志消息
	• %n 换⾏
	*/
	class Formatter
	{
	public:
		using ptr = std::shared_ptr< Formatter>;
		/*************构造析构************ */
		// pattern 模式
		/*
		Formatter()
			:_pattern("[%d{%H:%M:%S}][%t][%p][%c][%f:%l]%m%n")
		{
			assert(ParsePattern());
		}*/
		Formatter(const std::string pattern = "[%d{%H:%M:%S}][%t][%p][%c][%f:%l]%m%n") 
			:_pattern(pattern) 
		{
			assert(ParsePattern());
		}

		/*************成员函数************ */
		//对msg进行格式化
		void StreamFormat(std::ostream& out, Log_Msg& msg)
		{
			for (auto& it : _items)
			{
				it->Format(out,msg);
			}
		}
		
		std::string StringFormat(Log_Msg& msg)
		{
			std::stringstream lo_ss;
			for (auto& it : _items)
			{
				it->Format(lo_ss, msg);
			}
			return lo_ss.str();
		}
	private:

		//对格式化规则字符串进行解析
		//parse 解析
		bool ParsePattern()
		{
			//1.对格式化字符串的解析
			int lo_pos = 0;
			std::vector<std::pair<std::string, std::string>> lo_parse;
			std::string lo_row;
			std::string lo_key;
			std::string lo_val;
			while (lo_pos <= _pattern.size())
			{
				if (_pattern[lo_pos] == '%')
				{
					++lo_pos;
					if (lo_pos >= _pattern.size())
					{
						std::cout << "ERROR: 格式化字符串错误 CODE: 单独的'%'" << std::endl;
						return false;
					}
					// %% 判断
					if (_pattern[lo_pos] == '%')
					{
						lo_row += _pattern[lo_pos];
						++lo_pos;
						continue;
					}
					if (!lo_row.empty())
					{
						//lo_parse.push_back(std::make_pair(lo_row, ""));
						lo_parse.push_back(std::pair<std::string, std::string>(std::move(lo_row), ""));
						//lo_row.clear();
					}
					//获得key
					lo_key+= _pattern[lo_pos];
					++lo_pos;
					
					if (_pattern[lo_pos] == '{')
					{
						//Value有值
						while (lo_pos <= _pattern.size())
						{
							++lo_pos;
							if (lo_pos >= _pattern.size())
							{
								std::cout << "ERROR: 格式化字符串错误 CODE: '{'匹配失败" << std::endl;
								return false;
							}
							if (_pattern[lo_pos] == '}')
							{
								++lo_pos;
								break;
							}
							lo_val += _pattern[lo_pos];
						}
					}
					lo_parse.push_back(std::make_pair(std::move(lo_key), std::move(lo_val)));
					//lo_key.clear();
					//lo_val.clear();
				}
				else
				{
					lo_row += _pattern[lo_pos];
					++lo_pos;
				}
			}
			//2.根据解析得到的数据，初始化格式化子项中的成员
			for (auto &it : lo_parse)
			{
				_items.push_back(CreateItem(it.first, it.second));
			}
			return true;
		}


		//pattern解析
		bool parsePattern() {
			//std::string _pattern = "sg{}fsg%d{%H:%M:%S}%Tsdf%t%T[%p]%T[%c]%T%f:%l%T%m%n";
			//std::cout << _pattern << std::endl;
			//每个要素分为三部分：
			// 格式化字符 : %d %T %p...
			// 对应的输出⼦格式 ： {%H:%M:%S}
			// 对应数据的类型 ： 0-表⽰原始字符串，也就是⾮格式化字符，1-表⽰格式化数据类型
			// 默认格式 "%d{%H:%M:%S}%T%t%T[%p]%T[%c]%T%f:%l%T%m%n"
			std::vector<std::tuple<std::string, std::string, int>> arry;
			std::string format_key;//存放%后的格式化字符
			std::string format_val;//存放格式化字符后边 {} 中的⼦格式字符串
			std::string string_row;//存放原始的⾮格式化字符
			bool sub_format_error = false;
			int pos = 0;
			while (pos < _pattern.size()) {
				if (_pattern[pos] != '%') {
					string_row.append(1, _pattern[pos++]);
					continue;
				}
				if (pos + 1 < _pattern.size() && _pattern[pos + 1] == '%') {
					string_row.append(1, '%');
					pos += 2;
						continue;
				}
				if (string_row.empty() == false) {
					arry.push_back(std::make_tuple(string_row, "", 0));
					string_row.clear();
				}
				//当前位置是%字符位置
				pos += 1;//pos指向格式化字符位置
				if (pos < _pattern.size() && isalpha(_pattern[pos])) {
					format_key = _pattern[pos];//保存格式化字符
				}
				else {
					std::cout << &_pattern[pos - 1] << "位置附近格式错误！\n";
					return false;
				}
				//pos指向格式化字符的下⼀个位置，判断是否包含有⼦格式 %d{%Y-%m-%d}
				pos += 1;
				if (pos < _pattern.size() && _pattern[pos] == '{') {
					sub_format_error = true;
					pos += 1;//pos指向花括号下⼀个字符处
					while (pos < _pattern.size()) {
						if (_pattern[pos] == '}') {
							sub_format_error = false;
							pos += 1;//让pos指向}的下⼀个字符处
							break;
						}
						format_val.append(1, _pattern[pos++]);
					}
				}
				arry.push_back(std::make_tuple(format_key, format_val, 1));
				format_key.clear();
				format_val.clear();
			}
			if (sub_format_error) {
				std::cout << "{}对应出错\n";
				return false;
			}
			if (string_row.empty() == false)
				arry.push_back(std::make_tuple(string_row, "", 0));
			if (format_key.empty() == false)
				arry.push_back(std::make_tuple(format_key, format_val, 1));
			for (auto& it : arry) {
				if (std::get<2>(it) == 0) {
					Base_FormatItem::ptr fi(new OtherFormatItem(std::get<0>(it)));
					_items.push_back(fi);
				}
				else {
					Base_FormatItem::ptr fi = CreateItem(std::get<0>(it),
						std::get<1>(it));
						if (fi.get() == nullptr) {
							std::cout << "没有对应的格式化字符: %" << std::get<0>(it) <<
								std::endl;
							return false;
						}
					_items.push_back(fi);
				}
			}
			return true;
		}

		//根据不同的格式化字符创建不同的格式化子项
		Base_FormatItem::ptr CreateItem(const std::string& key, const std::string& value)
		{
			if (key == "m")return std::make_shared<MsgFormatItem>();
			if (key == "p")return std::make_shared<LevelFormatItem>();
			if (key == "c")return std::make_shared<NameFormatItem>();
			if (key == "t")return std::make_shared<ThreadFormatItem>();
			if (key == "n")return std::make_shared<NLineFormatItem>();
			if (key == "d")return std::make_shared<TimeFormatItem>();
			if (key == "f")return std::make_shared<CFileFormatItem>();
			if (key == "l")return std::make_shared<CLineFormatItem>();
			if (key == "T")return std::make_shared<TabFormatItem>();
			if (key == "") return std::make_shared<OtherFormatItem>();
			return std::make_shared<OtherFormatItem>(key);
		}
	private:
		std::string _pattern;//格式化规则字符串
		std::vector<Base_FormatItem::ptr> _items;
	};
}
